`include "mycpu.h"
module SimTop(
    input         clock,
    // input         resetn,
    input           reset,

    input  [63:0] io_logCtrl_log_begin,
    input  [63:0] io_logCtrl_log_end,
    input  [63:0] io_logCtrl_log_level,
    input         io_perfInfo_clean,
    input         io_perfInfo_dump,

    output        io_uart_out_valid,
    output [7:0]  io_uart_out_ch,
    output        io_uart_in_valid,
    input  [7:0]  io_uart_in_ch
    // inst sram interface
    // output        inst_sram_req,
    // output        inst_sram_wr,
    // output [ 1:0] inst_sram_size,
    // output [ 3:0] inst_sram_wstrb,
    // output [31:0] inst_sram_addr,
    // output [31:0] inst_sram_wdata,
    // input         inst_sram_addr_ok,
    // input         inst_sram_data_ok,
    // input  [31:0] inst_sram_rdata,
    // data sram interface
    // output        data_sram_req,
    // output        data_sram_wr,
    // output [ 1:0] data_sram_size,
    // output [ 3:0] data_sram_wstrb,
    // output [31:0] data_sram_addr,
    // output [31:0] data_sram_wdata,
    // input         data_sram_addr_ok,
    // input         data_sram_data_ok,
    // input  [31:0] data_sram_rdata,
    // trace debug interface
    // output [63:0] debug_wb_pc,
    // output        debug_wb_rf_wen,
    // output [ 4:0] debug_wb_rf_wnum,
    // output [63:0] debug_wb_rf_wdata,
);
// reg         reset;
// always @(posedge clk) reset <= ~resetn;
wire         clk;
assign clk = clock;
wire         ds_allowin;
wire         es_allowin;
wire         ms_allowin;
wire         ws_allowin;
wire         fs_to_ds_valid;
wire         ds_to_es_valid;
wire         es_to_ms_valid;
wire         ms_to_ws_valid;
// wire         ms_to_es_ex;
// wire         ws_to_es_ex;
wire         cr_flush_o;
wire         ms_will_to_ws;
wire         es_to_ms_cancel_first_back;
wire         ms_to_es_data_alok;
wire         ms_to_es_data_alok2;

wire        inst_sram_req;
wire        inst_sram_wr;
wire [ 1:0] inst_sram_size;
wire [ 3:0] inst_sram_wstrb;
wire [63:0] inst_sram_addr;
wire [31:0] inst_sram_wdata;
wire        inst_sram_addr_ok;
wire        inst_sram_data_ok;
wire [31:0] inst_sram_rdata;

wire        data_sram_req;
wire        data_sram_wr;
wire [ 1:0] data_sram_size;
wire [ 7:0] data_sram_wstrb;
wire [63:0] data_sram_addr;
wire [63:0] data_sram_wdata;
wire         data_sram_addr_ok;
wire         data_sram_data_ok;
wire [63:0] data_sram_rdata;

wire [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus;
wire [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus;
wire [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus;
wire [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus;
wire [`WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus;
wire [`BR_BUS_WD       -1:0] br_bus;
wire [`BPU_TO_DS_BUS_WD -1:0] bpu_to_ds_bus ;
wire [`DS_TO_BPU_BUS_WD -1:0] ds_to_bpu_bus;

wire [`WS_TO_CSR_BUS_WD -1:0] ws_to_csr_bus;
wire  [63:0]                  csr_rdata;
wire  [63:0]                  csr_flush_pc;
wire                          csr_MIE;
wire                          csr_MTIE;
wire                          time_int;
wire                          ws_to_es_flush;
wire                          ms_to_es_flush;

//forward
wire [`DS_TO_TH_BUS_WD -1:0] ds_to_th_bus;
wire [`ES_TO_TH_BUS_WD   -1:0] es_to_th_bus;
wire [`MS_TO_TH_BUS_WD   -1:0] ms_to_th_bus;
wire [`_TO_TH_BUS_WD   -1:0] ws_to_th_bus;

wire [`ES_TO_DS_BUS_WD -1:0] es_to_ds_bus;
wire [`_TO_DS_BUS_WD -1:0] ms_to_ds_bus;
wire [`_TO_DS_BUS_WD -1:0] ws_to_ds_bus;
wire [`ES_FLUSH_BUS_WD -1:0] es_flush_bus;


wire [`_OUT_TH_BUS_WD  -1:0] data_haza_bus;

//wire [`ES_TO_RF_BUS_WD -1:0] es_to_rfo_bus;
wire [`WS_TO_C0_BUS_WD -1:0]  ws_to_c0_bus;
wire [31:0]                   mfc0_out_data;
wire [32:0]                   cr_to_fs_bus;
wire [32:0]                   ms_to_cr_bus;
//wire [17:0]                   cr_to_ds_bus;
////difftest
wire [63:0]     regs [31:0];
wire [63:0] debug_wb_pc;
wire [31:0] debug_wb_inst;
wire        debug_wb_valid;
wire        debug_wb_rf_wen;
wire [ 4:0] debug_wb_rf_wnum;
wire [63:0] debug_wb_rf_wdata;
wire [63:0] a0_value;
wire        ws_skip;
wire       csr_flush_o;

wire [63:0] diff_mstatus;
wire [63:0] diff_mepc   ;
wire [63:0] diff_mtvec  ;
wire [63:0] diff_mcause ;
wire [63:0] diff_mip    ;
wire [63:0] diff_mie    ;

// IF stage
IF_stage if_stage(
    .clk            (clk            ),
    .reset          (reset          ),

    //allowin
    .ds_allowin     (ds_allowin     ),
    //br_bus
    .br_bus         (br_bus         ),
    // .cr_to_fs_bus   (cr_to_fs_bus),
    .ds_to_bpu_bus  (ds_to_bpu_bus),
    .es_flush_bus   (es_flush_bus),
    // .ms_to_fs_ex    (ms_to_fs_ex),
    // .ws_to_fs_ex    (ws_to_fs_ex),
    //outputs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    .bpu_to_ds_bus  (bpu_to_ds_bus),
    //csr_flush
    .csr_flush_o    (csr_flush_o),
    .csr_flush_pc   (csr_flush_pc),
    // inst sram interface
    .inst_sram_req   (inst_sram_req   ),
    .inst_sram_wr    (inst_sram_wr )  ,
    .inst_sram_size (inst_sram_size),
    .inst_sram_addr_ok (inst_sram_addr_ok),
    .inst_sram_data_ok (inst_sram_data_ok),
    .inst_sram_wstrb  (inst_sram_wstrb  ),
    .inst_sram_addr (inst_sram_addr ),
    .inst_sram_wdata(inst_sram_wdata),
    .inst_sram_rdata(inst_sram_rdata)
    
);

wire [63:0] rdata;
reg           inst_req;
reg [63:0]    pc;
reg inst_data_ok;
RAMHelper RAMHelper(
  .clk              (clk),
  .en               (inst_req),
  .rIdx             ((pc - `PC_START) >> 3),
  .rdata            (rdata),
  .wIdx             (0),
  .wdata            (0),
  .wmask            (0),
  .wen              (0)
);

always @(posedge clk) begin
    pc          <= inst_sram_addr;
    inst_req    <= inst_sram_req;
    inst_data_ok <= inst_sram_req; 
end
assign inst_sram_data_ok = inst_data_ok;
assign inst_sram_addr_ok = 1'b1;
assign inst_sram_rdata   = pc[2] ?  rdata[63:32] : rdata[31:0];


// ID stage
ID_stage id_stage(
    .clk            (clk            ),
    .reset          (reset          ),

    //allowin
    .es_allowin     (es_allowin     ),
    .ds_allowin     (ds_allowin     ),
    //from fs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    .bpu_to_ds_bus  (bpu_to_ds_bus),
    //to es
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //to fs
    .br_bus         (br_bus         ),
    .ds_to_bpu_bus  (ds_to_bpu_bus),

    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    .ds_to_th_bus   (ds_to_th_bus   ),

    .es_to_ds_bus   (es_to_ds_bus   ),
    .ms_to_ds_bus   (ms_to_ds_bus   ),
    .ws_to_ds_bus   (ws_to_ds_bus   ),
    .data_haza_bus  (data_haza_bus  ),
    //time_int//
    .time_int       (time_int       ),
    .csr_MIE        (csr_MIE        ),
    .csr_MTIE       (csr_MTIE       ),

    //.es_to_rfo_bus  (es_to_rfo_bus),
    .cr_flush_o     (es_flush_bus[64] | csr_flush_o),
//    .cr_to_ds_bus   (cr_to_ds_bus),
    .regs_o         (regs)

);
assign a0_value =regs[10];
assign io_uart_out_ch = a0_value[7:0];

// EXE stage
EXE_stage exe_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    //allowin
    .ms_allowin     (ms_allowin     ),
    .es_allowin     (es_allowin     ),
    .ms_will_to_ws  (ms_will_to_ws  ),
    //from ds
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //flush
    .es_flush_bus   (es_flush_bus),
    //to ms
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    .es_to_ms_cancel_first_back (es_to_ms_cancel_first_back),
    // data sram interface
    .data_sram_req   (data_sram_req   ),
    .data_sram_wr    (data_sram_wr),
    .data_sram_size   (data_sram_size),
    .data_sram_addr_ok (data_sram_addr_ok),
    .data_sram_data_ok (data_sram_data_ok),
    .data_sram_wstrb  (data_sram_wstrb  ),
    .data_sram_addr (data_sram_addr ),
    .data_sram_rdata  (data_sram_rdata),
    .data_sram_wdata(data_sram_wdata),

    .es_to_ds_bus   (es_to_ds_bus   ),
    .es_to_th_bus    (es_to_th_bus),
    .ms_to_es_data_alok2 (ms_to_es_data_alok2),
    .ms_to_es_data_alok  (ms_to_es_data_alok),

    //.es_to_rfo_bus      (es_to_rfo_bus),
    .ms_to_es_flush        (ms_to_es_flush),
    .ws_to_es_flush        (ws_to_es_flush),
    .cr_flush_o     (csr_flush_o)
);
reg [63:0] data_addr;
reg [7:0]  data_wstrb;
reg        data_wr;
reg        data_req;
reg        data_data_ok;
reg [63:0] data_wdata;
wire[63:0] data_wmask;
wire[63:0] ram_rdata;
reg        sel_clint;
wire       is_clint;

RAMHelper d_RAMHelper(
  .clk              (clk),
  .en               (data_req && !sel_clint),
  .rIdx             ((data_addr - `PC_START) >> 3),
  .rdata            (ram_rdata),
  .wIdx             ((data_addr - `PC_START) >> 3),
  .wdata            (data_wdata),
  .wmask            (data_wmask),
  .wen              (data_wr && data_req && !is_clint)
);
assign data_wmask = {{8{data_wstrb[7]}},
                     {8{data_wstrb[6]}},
                     {8{data_wstrb[5]}},
                     {8{data_wstrb[4]}},
                     {8{data_wstrb[3]}},
                     {8{data_wstrb[2]}},
                     {8{data_wstrb[1]}},
                     {8{data_wstrb[0]}}};

always @(posedge clk) begin
    data_req <= data_sram_req;
    data_wstrb <= data_sram_wstrb;
    data_wr  <= data_sram_wr;
    data_addr  <= data_sram_addr;
    data_wdata <= data_sram_wdata;
    data_data_ok <=data_sram_req;
    sel_clint    <= is_clint;    
end
assign data_sram_addr_ok = 1'b1;
assign data_sram_data_ok = sel_clint ? 1'b1 :  data_data_ok;
assign data_sram_rdata   = sel_clint ? clint_rdata : ram_rdata;

wire          clint_data_ok;
wire [63:0]   clint_rdata;


assign is_clint = data_sram_addr == 64'h0000_0000_0200_4000 || data_sram_addr == 64'h0000_0000_0200_bff8;

// CLINT //
clint u_clint (
    .clk          (clk),
    .reset        (reset),
    .req          (data_sram_req),
    .addr         (data_sram_addr),
    .wr           (data_sram_wr),
    .wstrb        (data_sram_wstrb),
    .wdata        (data_sram_wdata),
    .clint_data_ok (clint_data_ok),
    .time_int      (time_int),
    .clint_rdata  (clint_rdata)
);



// MEM stage
MEM_stage mem_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    //allowin
    .ws_allowin     (ws_allowin     ),
    .ms_allowin     (ms_allowin     ),
    .ms_will_to_ws  (ms_will_to_ws ),
    //from es
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    .es_to_ms_cancel_first_back (es_to_ms_cancel_first_back),
    //to ws
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //from data-sram
    .data_sram_data_ok (data_sram_data_ok),
    .data_sram_rdata(data_sram_rdata),
    .data_sram_addr_ok (data_sram_addr_ok),
    .data_sram_req      (data_sram_req),

    .ms_to_es_data_alok2 (ms_to_es_data_alok2),
    .ms_to_es_data_alok  (ms_to_es_data_alok),



    .ms_to_ds_bus   (ms_to_ds_bus   ),
    .ms_to_th_bus    (ms_to_th_bus),
    .ms_to_es_flush  (ms_to_es_flush),
    .cr_flush_o     (csr_flush_o),
    .ms_to_cr_bus    (ms_to_cr_bus)
);
// WB stage
//assign debug_wb_pc <=32'bfffffffe;
WB_stage wb_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    //allowin
    .ws_allowin     (ws_allowin     ),
    //from ms
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //to fs
    // .ws_to_fs_ex    (ws_to_fs_ex),
    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    .ws_skip        (ws_skip        ),
    //trace debug interface
    .debug_wb_inst    (debug_wb_inst   ),
    .debug_wb_valid   (debug_wb_valid  ),
    .debug_wb_pc      (debug_wb_pc      ),
    .debug_wb_rf_wen  (debug_wb_rf_wen  ),
    .debug_wb_rf_wnum (debug_wb_rf_wnum ),
    .debug_wb_rf_wdata(debug_wb_rf_wdata),

    .ws_to_ds_bus   (ws_to_ds_bus   ),
    .ws_to_th_bus    (ws_to_th_bus  ),
    .ws_to_es_flush   (ws_to_es_flush),
    .csr_rdata      (csr_rdata),
    .ws_to_csr_bus  (ws_to_csr_bus),
    // .ws_to_c0_bus    (ws_to_c0_bus),
    .ws_io_uart_out_valid (io_uart_out_valid),
    .cr_flush_o    (csr_flush_o)
);

// //TH stage
TH_stage th_stage(
    .ds_to_th_bus    (ds_to_th_bus),
    .es_to_th_bus    (es_to_th_bus),
    .ms_to_th_bus    (ms_to_th_bus),
    .ws_to_th_bus    (ws_to_th_bus),
    //冲突检测单元返回的信号
    .data_haza_bus    (data_haza_bus)
    
);
// assign cr_flush_o = 1'b0;
wire [3:0] diff_intrNO;
wire [3:0] diff_cause;
csr u_csr (
    .clk            (clk),
    .reset          (reset),
    .ws_to_csr_bus  (ws_to_csr_bus),
    .csr_rdata      (csr_rdata),
    .csr_flush_pc   (csr_flush_pc),
    .csr_flush_o    (csr_flush_o),
    .csr_MIE        (csr_MIE),
    .csr_MTIE       (csr_MTIE),
    ////diff_test////
    .diff_intrNO    (diff_intrNO),
    .diff_cause     (diff_cause),
    .diff_mstatus   (diff_mstatus),
    .diff_mepc      (diff_mepc),
    .diff_mtvec     (diff_mtvec),
    .diff_mcause    (diff_mcause),
    .diff_mip       (diff_mip),
    .diff_mie       (diff_mie)

);
reg [63:0]    mstatus;
reg [63:0]    mepc;
reg [63:0]    mtvec;
reg [63:0]    mcause;
reg [63:0]    mip;
reg [63:0]    mie;
reg [3:0]     intrNO;
reg [3:0]     cause;
wire[63:0]    diff_sstatus;

always @( posedge clk) begin
  if (reset) begin
    mstatus <= 64'b0;
    mepc    <= 64'b0;
    mtvec   <= 64'b0;
    mcause  <= 64'b0;
    mip     <= 64'b0;
    mie     <= 63'b0;
    intrNO  <= 4'h0;
    cause   <= 4'h0;
  end
  else begin
    mstatus <= diff_mstatus;
    mepc    <= diff_mepc   ;
    mtvec   <= diff_mtvec  ;
    mcause  <= diff_mcause ;
    mip     <= diff_mip    ;
    mie     <= diff_mie    ;
    intrNO  <= diff_intrNO ;
    cause   <= diff_cause  ;

  end
  
end
assign diff_sstatus = diff_mstatus & 64'h8000_0003_000D_E122;


// cpu0  cpu0(
//     .clk            (clk            ),
//     .reset          (reset          ),
//     .ext_int_in     (6'b0           ),
//     .ws_to_c0_bus   (ws_to_c0_bus),
//     .mfc0_out_data  (mfc0_out_data),
//     .cr_to_fs_bus   (cr_to_fs_bus),
//     .cr_flush_o     (cr_flush_o),
//     .ms_to_cr_bus   (ms_to_cr_bus),
//     .cr_to_ds_bus   (cr_to_ds_bus)
// );




// Difftest
reg cmt_wen;
reg cmt_skip;
reg [7:0] cmt_wdest;
reg [`REG_BUS] cmt_wdata;
reg [`REG_BUS] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`REG_BUS] regs_diff [31 : 0];

wire inst_valid = (debug_wb_pc != `PC_START) | (debug_wb_inst != 0);

always @(negedge clk) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt,cmt_skip} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= debug_wb_rf_wen;
    cmt_wdest <= {3'd0, debug_wb_rf_wnum};
    cmt_wdata <= debug_wb_rf_wdata;
    cmt_pc <= debug_wb_pc;
    cmt_inst <= debug_wb_inst;
    cmt_valid <= debug_wb_valid;

		regs_diff <= regs;

    trap <= debug_wb_inst[6:0] == 7'h6b ;
    trap_code <= regs[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + inst_valid;
    cmt_skip <= ws_skip;
  end
end

DifftestInstrCommit DifftestInstrCommit(
  //我的情况是这个需要延时一拍提交
  //也就是过一个寄存器
  .clock              (clk),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .skip               (cmt_skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  ////我的情况是这个需要延时一拍提交
  //也就是过一个寄存器
  .clock              (clk),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  //////我的情况是这个  不  需要延时一拍提交
  //直接从写回接出来就行（wire类型
  .clock              (clk),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

DifftestArchEvent DifftestArchEvent (
  //////我的情况是这个  不  需要延时一拍提交
  //直接从写回接出来就行（wire类型
    .clock              (clk),
    .coreid             (0),  
    .intrNO             (diff_intrNO),//中断号
    .cause              (diff_cause),//例外号，非中断号
    .exceptionPC        (debug_wb_pc ),
    .exceptionInst     (debug_wb_inst)
);

DifftestCSRState DifftestCSRState(
  .clock              (clk),
  .coreid             (0),
  .priviledgeMode     (3),
  .mstatus            (diff_mstatus),
  .sstatus            (diff_sstatus),
  .mepc               (diff_mepc),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (diff_mtvec),
  .stvec              (0),
  .mcause             (diff_mcause),
  .scause             (0),
  .satp               (0),
  .mip                (mip),
  .mie                (diff_mie),
  .mscratch           (0),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clk),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);

endmodule

